//
// Created by LoveHoneyYou on 2024-11-16.
//

#include "EpollDispatcher.h"
#include <csignal>

EpollDispatcher::EpollDispatcher(EventLoop *event_loop)
                : Dispatcher(event_loop)
{
    epfd_ = epoll_create(10);
    if(epfd_ == -1)
    {
        perror("epoll_create error");
        exit(0);
    }

    events_ = new struct epoll_event[Max_Node_];
    name_ = "Epoll";
}

EpollDispatcher::~EpollDispatcher()
{
    close(epfd_);
    delete []events_;
}

int EpollDispatcher::Add()
{
    int ret = Epoll_Ctl(EPOLL_CTL_ADD);
    if(ret == -1)
    {
        perror("epoll_ctl_add");
        exit(0);
    }
    return ret;
}

int EpollDispatcher::Remove()
{
    int ret = Epoll_Ctl(EPOLL_CTL_DEL);
    if(ret == -1)
    {
        perror("epoll_ctl delete");
        exit(0);
    }

    channel_->destroy_callback_((void*)channel_->Get_Arg());
    return ret;
}

int EpollDispatcher::Modify()
{
    int ret = Epoll_Ctl(EPOLL_CTL_MOD);
    if(ret == -1)
    {
        perror("epoll_ctl modify");
        exit(0);
    }
    return ret;
}

int EpollDispatcher::Dispatch(int timeout)
{
    int count = epoll_wait(epfd_,events_,Max_Node_,timeout*1000);
    for(int i = 0; i < count; ++i)
    {
        int events = events_[i].events;
        int fd = events_[i].data.fd;
        if(events & EPOLLERR || events & EPOLLHUP)
        {
            continue;
        }

        if(events & EPOLLIN)
        {
            event_loop_->Event_Active(fd,(int)FD_Event::ReadEvent);
        }

        if(events & EPOLLOUT)
        {
            event_loop_->Event_Active(fd,(int)FD_Event::WriteEvent);
        }
    }
    return 0;
}

int EpollDispatcher::Epoll_Ctl(int op)
{
    struct epoll_event ev;
    ev.data.fd = channel_->Get_Socket();
    int events = 0;
    if(channel_->Get_Event() & (int)FD_Event::ReadEvent)
    {
        events |= EPOLLIN;
    }

    if(channel_->Get_Event() & (int)FD_Event::WriteEvent)
    {
        events |= EPOLLOUT;
    }

    ev.events = events;
    int ret = epoll_ctl(epfd_,op,channel_->Get_Socket(),&ev);
    return ret;
}
